#include "ct_config.h"
#include "ct_adc.h"
/*****************************************************************************
 * Private Functions
 ****************************************************************************/

/*****************************************************************************
 * Public Functions
 ****************************************************************************/
void ct_adc_Init(void) {
    ADC_ConvertTime(CT_ADC_ADCDIV2, CT_ADC_ADCAQT5);
    //
#ifdef CT_CONTINUOUS_MODE
    // ADC_InitialContinous(ADC_CONVERSION_RATE_1, 1, ADCSlowSpeed);
    ct_adc_ContInit(&adc_ContData);
#endif
    ct_adc_Open();
}

void ct_adc_Open(void) {
    set_ADCCON1_ADCEN; /* enable ADC circuit*/
}

void ct_adc_Close(void) {
    clr_ADCCON1_ADCEN; /* disable ADC circuit*/
}

unsigned int ct_adc_SingleRead(unsigned char channel) {
    unsigned char i;
    unsigned int  min1 = 0x0FFF, min2 = 0x0FFF;
    unsigned int  max1 = 0, max2 = 0, sum = 0;
    unsigned int  value;
    unsigned int  valid_samples = 0;

    DISABLE_ADC;
    switch (channel)    // ADC input channel digtial function disable
    {
#ifdef CT_ADC_CH0
        case 0:
            ENABLE_ADC_CH0;
            break;
#endif
#ifdef CT_ADC_CH1
        case 1:
            ENABLE_ADC_CH1;
            break;
#endif
#ifdef CT_ADC_CH2
        case 2:
            ENABLE_ADC_CH2;
            break;
#endif
#ifdef CT_ADC_CH3
        case 3:
            ENABLE_ADC_CH3;
            break;
#endif
#ifdef CT_ADC_CH4
        case 4:
            ENABLE_ADC_CH4;
            break;
#endif
#ifdef CT_ADC_CH5
        case 5:
            ENABLE_ADC_CH5;
            break;
#endif
#ifdef CT_ADC_CH6
        case 6:
            ENABLE_ADC_CH6;
            break;
#endif
#ifdef CT_ADC_CH7
        case 7:
            ENABLE_ADC_CH7;
            break;
#endif
#ifdef CT_ADC_CH10
        case 10:
            ENABLE_ADC_CH10;
            break;
#endif
#ifdef CT_ADC_CH11
        case 11:
            ENABLE_ADC_CH11;
            break;
#endif
#ifdef CT_ADC_CH12
        case 12:
            ENABLE_ADC_CH12;
            break;
#endif
#ifdef CT_ADC_CH13
        case 13:
            ENABLE_ADC_CH13;
            break;
#endif
#ifdef CT_ADC_CH14
        case 14:
            ENABLE_ADC_CH14;
            break;
#endif
#ifdef CT_ADC_CH15
        case 15:
            ENABLE_ADC_CH15;
            break;
#endif
#ifdef CT_ADC_VBG
        case VBG:
            ENABLE_ADC_BANDGAP;
            break;
#endif
#ifdef CT_ADC_VTEMP
        case VTEMP:
            ENABLE_ADC_VTEMP;
            break;
#endif
#ifdef CT_ADC_VLDO
        case VLDO:
            ENALBE_ADC_VLDO;
            break;
#endif
        default:
            break;
    }

    for (i = 0; i < 10; i++) {
        /*start bandgap ADC */
        clr_ADCCON0_ADCF;
        set_ADCCON0_ADCS;    // ADC start trig signal
        nop;
        nop;
        while (!(ADCCON0 & SET_BIT7))
            ;

        value = (ADCRH << 4) + (ADCRL & 0x0F);

        if (i >= 2) {
            if (value < min1) {
                min2 = min1;
                min1 = value;
            } else if (value < min2) {
                min2 = value;
            }

            if (value > max1) {
                max2 = max1;
                max1 = value;
            } else if (value > max2) {
                max2 = value;
            }

            sum += value;
        }
    }

    sum = sum - min1 - min2 - max1 - max2;
    sum = sum >> 2;

    return sum;
}

#ifdef CT_CONTINUOUS_MODE

typedef struct {
    int8_t xdata *ResultTable;
    uint8_t       size;
    uint8_t       bADC_ContFinished;
} ADC_ContinueData;

ADC_Data adc_ContData;

#define ADC_CONT_DATA_SIZE 256
#define ADC_CONT_DATA_ADDR 0x300
int8_t xdata ResultTable[ADC_CONT_DATA_SIZE] _at_ ADC_CONT_DATA_ADDR;

void ct_adc_ContInit(ADC_Data *adc_ContData) {
    adc_ContData->ResultTable       = ResultTable;
    adc_ContData->size              = sizeof(ResultTable) / 2;
    adc_ContData->bADC_ContFinished = 0;

    ADC_InitialContinous(ADC_CONT_DATA_ADDR, adc_ContData->size, ADCHighSpeed);    // Define data restore in RAM start address and ADC total sample number
    ADC_Interrupt(Enable, ADC_INT_CONTDONE);
    set_ADCCON0_ADCS;    // Trig ADCS bit to start ADC
}

void ADC_ISR(void) interrupt 11 {
    _push_(SFRS);

    clr_ADCCON0_ADCF;

    if (adc_ContData->bADC_ContFinished == 0) {
        adc_ContData->bADC_ContFinished = 1;
    }

    _pop_(SFRS);
}

/**
 * @brief
 *
 * @param channel
 * @param dat
 * @return uint16_t
 */
uint16_t ct_adc_ContRead(uint8_t channel, ADC_Data *dat) {
    uint16_t temp = 0;
    uint8_t  i;
    if (dat->bADC_ContFinished) {
        for (i = 0; i < dat->size; i++) {
            temp = (dat->ResultTable[i] << 4) + (dat->ResultTable[i / 2 + dat->size] & 0x0F);
            i++;
            if (i < dat->size) {
                temp += (dat->ResultTable[i] << 4) + ((dat->ResultTable[(i - 1) / 2 + dat->size] >> 4) & 0x0F);
            }

            if (i == dat->size - 1) {
                dat->bADC_ContFinished = 0;
            }
        }
    }
    set_ADCCON0_ADCS;    // Trig ADCS bit to start ADC

    return temp;
}

#endif
